package 富婆梦.第一阶段.数值操作练习;

import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Random;

import static javafx.scene.input.KeyCode.L;

/**
 * 因为协议使用的基本单位都是byte
 * 所以该该类中要实现以下转换功能要求
 * 1.各种类型的主数据类型和byte的关系->使用byte数组保存各种主数据类型
 * 基本信息
 * 1 byte = 8-bit
 * 8-bit: 0000 0000
 * 需要掌握：位运算位移
 * << 操作
 * >> 操作
 * & 操作
 * | 操作
 * ^ 操作
 */
public class ByteTest {
    public static void main(String[] args) {
        Random random = new Random();
        //byte b = 123;


        // 测试各种基本数据类型与byte的关系
        //testPrimateDataFormat();

        //测试1：测试将布尔转换的
        boolean[] booleanValues = {true, false, true, false, true, false, true, true};
        byte saveToByte = boolSaveToByte(booleanValues);
        if (checkBooleanValueByIndex(saveToByte, 0)==booleanValues[0]
                &&checkBooleanValueByIndex(saveToByte, 1)==booleanValues[1]
                &&checkBooleanValueByIndex(saveToByte, 2)==booleanValues[2]
                &&checkBooleanValueByIndex(saveToByte, 3)==booleanValues[3]
                &&checkBooleanValueByIndex(saveToByte, 4)==booleanValues[4]
                &&checkBooleanValueByIndex(saveToByte, 5)==booleanValues[5]
                &&checkBooleanValueByIndex(saveToByte, 6)==booleanValues[6]
                &&checkBooleanValueByIndex(saveToByte, 7)==booleanValues[7]){
            System.out.println("Boolean类型和byte转换成功！");
        }

        //测试2：测试short转换
        short shortV = (short) random.nextInt();
        byte[] shortBytes = shortToByteArray(shortV);
        short toShortV = byteArrayToShort(shortBytes);
        if (shortV == toShortV) {
            System.out.println("使用随机生成的short 和 byte 的互相转换成功！");
        } else {
            System.out.println("使用随机生成的short 和 byte 的互相转换失败！ shortV=" + shortV + "  toShortV=" + toShortV);
        }

        //测试3：测试int转换
        int anInt = random.nextInt();
        byte[] intBytes = intToByteArray(anInt);
        int toInt = byteArrayToInt(intBytes);
        assert anInt == toInt;
        if (anInt == toInt) {
            System.out.println("使用随机生成的int 和 byte 的互相转换成功！");
        } else {
            System.out.println("使用随机生成的int 和 byte 的互相转换失败！");
        }

        //测试4：测试long转换
        long aLong = random.nextLong();
        byte[] longBytes = longToByteArray(aLong);
        long toLong = byteArrayToLong(longBytes);
        if (aLong == toLong) {
            System.out.println("使用随机生成的Long 和 byte 的互相转换成功！");
        } else {
            System.out.println("使用随机生成的Long 和 byte 的互相转换失败！");
        }
    }
    private static void testPrimateDataFormat() {
        Random random = new Random();

        // =======================================
        // char 类型 -》 char 使用1 个byte表示
        char s = 'j';
        byte charToByte = charToByte(s);
        char aChar = byteToChar(charToByte);
        if (s == aChar) {
            System.out.println("char 和 byte 的互相转换成功！");
        } else {
            System.out.println("char 和 byte 的互相转换失败！");
        }
        assert s == aChar;

        // =======================================
        // short 值  -》short 使用2 个byte表示
        //short shortV = (short) random.nextInt();
        short shortV = 555;
        byte[] shortBytes = shortToByteArray(shortV);
        short toShortV = byteArrayToShort(shortBytes);
        if (shortV == toShortV) {
            System.out.println("short 和 byte 的互相转换成功！");
        } else {
            System.out.println("short 和 byte 的互相转换失败！");
        }

        assert shortV == toShortV;


        // =======================================
        // int 值 -》使用4 个byte表示
        int anInt = 100;
        //int anInt = random.nextInt();
        byte[] intBytes = intToByteArray(anInt);
        int toInt = byteArrayToInt(intBytes);
        assert anInt == toInt;
        if (anInt == toInt) {
            System.out.println("int 和 byte 的互相转换成功！");
        } else {
            System.out.println("int 和 byte 的互相转换失败！");
        }

        // =======================================
        // long 值 -》使用8 个byte表示
        long aLong = 100;
        //long aLong = random.nextLong();
        // 用byte数组表示long
        byte[] longBytes = longToByteArray(aLong);
        // 读取byte数组表示的long值
        long toLong = byteArrayToLong(longBytes);
        // 校验正确性
        if (aLong == toLong) {
            System.out.println("Long 和 byte 的互相转换成功！");
        } else {
            System.out.println("Long 和 byte 的互相转换失败！");
        }
        assert (aLong == toLong);

        // =======================================
        // 这个比上面的难一些
        // boolean 值 true 或 false。使用一个byte表示。但其实只需要其中一个bit就可以
        // 生成测试数据
        boolean[] booleanValues = {
                random.nextBoolean(), random.nextBoolean(), random.nextBoolean(), random.nextBoolean(),
                random.nextBoolean(), random.nextBoolean(), random.nextBoolean(), random.nextBoolean()
        };
        // 使用一个byte保存8个boolean的状态
        byte saveToByte = boolSaveToByte(booleanValues);
        // 进行存储的校验
        for (int i = 0; i < booleanValues.length; i++) {
            // 判断根据索引，每个boolean都保存正常
            assert checkBooleanValueByIndex(saveToByte, i) == booleanValues[i];
        }


    }


    private static byte boolSaveToByte(boolean[] booleanValue) {
        if (booleanValue.length != 8) {
            throw new RuntimeException("非法输入");
        }
        byte bits = 0;
        // TODO：使用一个byte保存8个boolean的结果
        //一个byte的二进制保存形式是：0000 0000   正好用来保存8个布尔类型
        //运算符“|”代表或，即：1|0=1
        //保存布尔类型时，从右边开始保存，
        //如果第一个类型为true，则运算内容为 bits=0000 0000 | 0000 0001 =0000 0001
        //如果第二个类型还是为true，则运算内容为 bits=0000 0001 | 0000 0010 =0000 0011
        //如果第三个类型还是为true，则运算内容为 bits=0000 0011 | 0000 0100 =0000 0111
        //以此类推
        for (int i = 0; i < booleanValue.length; i++) {
            if (booleanValue[i] == true) {
                bits = (byte) (bits | (byte) Math.pow(2, i));
            }
        }
        System.out.print("将8个Boolean类型存储为byte（从右往左存储）：");
        PrintByte.printByte(bits);
        return bits;

    }

    private static boolean checkBooleanValueByIndex(byte bits, int index) {
        if (index < 0 || index > 7) {
            throw new RuntimeException("非法输入");
        }
        // TODO: 根据索引0-7，返回bits中保存的状态0/1
        //bits=1111 0110  index从右往左分别是，0,1,2,3,4,5,6,7
        //想要判断 1还是0，只需要使用符号&  因为：1 & 0 = 0，1 & 1 = 1
        //index=0,右边第一位：bits = 1111 0110 & 0000 0001 = 0000 0000
        //index=1,右边第二位：bits = 1111 0110 & 0000 0010 = 0000 0010    最终需要右移1位
        //index=2,右边第三位：bits = 1111 0110 & 0000 0100 = 0000 0100    最终需要右移2位
        // 逻辑右移：>>> 缺的地方全都补0
        int i = ((bits & (byte) Math.pow(2, index)) & 0xFF) >>> index;
        if (i == 1) {
            return true;
        }
        return false;

        //return (bits & (byte) Math.pow(2, index)) == Math.pow(2, index);
    }

    private static byte charToByte(char value) {

        // TODO： 实现char值对应的byte
        return (byte) value;
    }

    private static char byteToChar(byte b) {
        // TODO: byte转为char
//        int hi = (b[0] & 0xFF) << 8;
//        int lo = b[1] & 0xFF;
//        System.out.println((char)(hi|lo));
//        return (char)(hi|lo);
        return (char) b;
    }

    private static byte[] shortToByteArray(short value) {
        byte[] bytes = new byte[2];
        // TODO： short的byte数组表示
        //一个short等于两个byte即：1111 1000 0000 1100
        // 0XFF = 1111 1111
        //先拿到右边的一个byte
        //System.out.println("short的值是："+value);
        byte rightByte = (byte) (value & 0XFF);
        bytes[0] = rightByte;
        //拿到左边的一个byte，右移8位，就能得到
        byte leftByte = (byte) (value >>> 8);
        bytes[1] = leftByte;
        return bytes;
    }

    private static short byteArrayToShort(byte[] bytes) {
        // TODO: 把2位长度的byte数组转化为对应的short值
        //bytes数组：第一位，存储的short的右边，低8位
        //           第二位，存储的short的左边，高8位
        int i = bytes[1] << 8;
        // 向上转型 byte -> int  语言保证，数学含义上的值一致：如果是正值：没有影响，如果是负值，则二进制需要改变才能表示对应的数值
        // 向下转型 int -> byte 是截取
        int aByte = bytes[0] & 0XFF;
        short value = (short) (i | aByte);

        return value;
    }

    private static byte[] intToByteArray(int value) {

        byte[] bytes = new byte[4];
        // TODO： int的byte数组表示
        // 一个int需要4个byte表示，即：aaaa aaaa  bbbb bbbb  cccc cccc  dddd dddd

        // 从右边开始存储数据
        // 存储第一个byte，int的dddd dddd
        bytes[0] = (byte) value;

        // 存储第二个byte，int的cccc cccc
        bytes[1] = (byte) (value >>> 8);

        // 存储第三个byte，int的 bbbb bbbb
        bytes[2] = (byte) (value >>> 16);

        // 存储第四个byte，int的 aaaa aaaa
        bytes[3] = (byte) (value >>> 24);

        return bytes;
    }

    private static int byteArrayToInt(byte[] bytes) {
        // TODO: 把4位长度的byte数组转化为对应的int值
        // 从右边开始存储数据,数组第一位存的是最右边的低位
        // 一个int：aaaa aaaa  bbbb bbbb  cccc cccc  dddd dddd
        // bytes[3] 存储的是 aaaa aaaa
        int value_3 = bytes[3] << 24;
        //       0XFF0000转换为int：00000000 11111111 00000000 00000000
        //bytes[2]为负数时转化为int：11111111 11000000 00000000 00000000
        int value_2 = (bytes[2] << 16) & 0XFF0000;

        //         0XFF00转换为int：00000000 00000000 11111111 00000000
        //bytes[1]为负数时转化为int：11111111 11111111 11000000 00000000
        int value_1 = (bytes[1] << 8) & 0XFF00;
        int value_0 = bytes[0] & 0xFF;

        int value = (value_0 | value_1 | value_2 | value_3);
        return value;
    }


    private static byte[] longToByteArray(long value) {
        byte[] bytes = new byte[8];
        // TODO： 实现long值用8位长度的byte数组存储：long值其实就是8byte来表示的
        // 一个long需要8个byte表示，即：aaaa aaaa  bbbb bbbb  cccc cccc  dddd dddd  eeee eeee  ffff ffff  gggg gggg  hhhh hhhh
        // 从右边开始存储数据
        // 存储第一个byte，int的 hhhh hhhh
        bytes[0] = (byte) value;

        // 存储第二个byte，int的 gggg gggg
        bytes[1] = (byte) (value >> 8);

        // 存储第三个byte，int的 ffff ffff
        bytes[2] = (byte) (value >> 16);

        // 存储第四个byte，int的 eeee eeee
        bytes[3] = (byte) (value >> 24);

        // 存储第五个byte，int的 dddd dddd
        bytes[4] = (byte) (value >> 32);

        // 存储第六个byte，int的 cccc cccc
        bytes[5] = (byte) (value >> 40);

        // 存储第七个byte，int的 bbbb bbbb
        bytes[6] = (byte) (value >> 48);

        // 存储第八个byte，int的 aaaa aaaa
        bytes[7] = (byte) (value >> 56);

        return bytes;
    }

    private static long byteArrayToLong(byte[] bytes) {
        // TODO: 把8位长度的byte数组转化为对应的long值
        // 从右边开始存储数据,数组第一位存的是最右边的低位
        //一个long需要8个byte表示，即：aaaa aaaa  bbbb bbbb  cccc cccc  dddd dddd  eeee eeee  ffff ffff  gggg gggg  hhhh hhhh
        // bytes[3] 存储的是 aaaa aaaa

        long value_7 = ((0xFFL & bytes[7]) << 56);
        long value_6 = ((0xFFL & bytes[6]) << 48);
        long value_5 = ((0xFFL & bytes[5]) << 40);
        long value_4 = ((0xFFL & bytes[4]) << 32);
        long value_3 = ((0xFFL & bytes[3]) << 24);
        long value_2 = ((0xFFL & bytes[2]) << 16);
        long value_1 = ((0xFFL & bytes[1]) << 8);
        long value_0 = (0xFFL & bytes[0]);

        long value = (value_0 + value_1 + value_2 + value_3 + value_4 + value_5 + value_6 + value_7);

        return value;
    }

}
